// 演示日志系统的扩展方法

#include "../logsystem/log.hpp"
#include <unistd.h>

/*
    滚动时间间隔
     秒、分、时、天
*/
enum class Type
{
    ROLL_SECOND,
    ROLL_MINUTE,
    ROLL_HOUR,
    ROLL_DAY
};

// 扩展
// 滚动文件（按时间间隔滚动）
class RollByTimeSink : public Yohifo::LogSink
{
public:
    RollByTimeSink(const std::string basename, Type type)
        : _basename(basename)
    {
        switch(type)
        {
            case Type::ROLL_SECOND:
                _gap_size = 1;
            break;
            case Type::ROLL_MINUTE:
                _gap_size = 1 * 60;
            break;
            case Type::ROLL_HOUR:
                _gap_size = 1 * 60 * 60;
            break;
            case Type::ROLL_DAY:
                _gap_size = 1 * 60 * 60 * 24;
            break;
            default:
                _gap_size = 1 * 60; // 默认按分钟滚动
            break;
        }

        // 根据 gap 设置滚动时间段
        _cur_gap = Yohifo::Util::Date::getTime() % _gap_size;

        OpenFile();
    }

    ~RollByTimeSink()
    {
        // 关闭已打开的文件
        _ofs.close();
    }

    void log(const char *data, size_t len) override
    {
        // 如果(当前的时间段)等于(预设的滚动时间段)，打开新文件再写入
        time_t gap = Yohifo::Util::Date::getTime() % _gap_size;
        if (gap == _cur_gap)
        {
            // 1.关闭原来的老文件
            _ofs.close();

            // 2.打开新的文件
            OpenFile();
        }

        // 可以正常写入数据
        _ofs.write(data, len);
        assert(_ofs.good());
    }

private:
    std::string CreateNewFile()
    {
        const time_t t = Yohifo::Util::Date::getTime(); // 获取当前时间戳

        // 创建时间相关信息结构体
        struct tm *pt = localtime(&t);

        // 利用文件流对象，将时间成员快速转换为字符串
        std::stringstream ss;
        ss << _basename;
        ss << pt->tm_year + 1900;
        ss << pt->tm_mon + 1;
        ss << pt->tm_mday;
        ss << pt->tm_hour;
        ss << pt->tm_min;
        ss << pt->tm_sec;
        ss << ".log";

        return ss.str();
    }

    void OpenFile()
    {
        // 1.首先获取带有当前时间的日志文件
        std::string pathname = CreateNewFile();

        // 2.创建目录
        Yohifo::Util::File::createDirectory(Yohifo::Util::File::path(pathname));

        // 3.打开文件（追加）
        _ofs.open(pathname, std::ios::binary | std::ios::app);
        assert(_ofs.is_open());
    }

private:
    std::string _basename; // 传入 ./log/base- 根据当前时间补全文件后缀并创建文件
    std::ofstream _ofs;    // 文件句柄
    time_t _gap_size;     // 单次间隔时间段大小
    time_t _cur_gap;     // 当前时间段
};

// 日志器格式匹配符
// 时间、日志器、线程ID、源文件名称、源文件行号、日志等级、制表符、日志主体消息、换行
// %d    %c     %t      %f         %l          %p       %T     %m           %n
// 时间：年 %Y 月 %m 日 %d 时 %H 分 %M 秒 %S
//   - 在 %d 之后，需要添加 {具体的时间格式}

int main()
{
    // 创建日志器建造者对象(可选择 局部/全局 )
    std::shared_ptr<Yohifo::LoggerBuilder> builder(new Yohifo::LocalLoggerBuilder);
    builder->BuildLoggerType(Yohifo::LoggerType::LOGGER_SYNC); // 设置日志器类型( 同步/异步 ) [可省略]
    // builder->BuildAsyncType(Yohifo::AsyncType::ASYNC_SAFE); // 如果为异步日志器，需要设置 安全/非安全 模式 [可省略]
    builder->BuildLoggerName("TestSyncLogger"); // 日志器名称 [不可省略]
    builder->BuildLoggerLimit(Yohifo::LogLevel::Value::DEBUG); // 限制最低输出等级 [不可省略]
    builder->BuildFormat("<%p>[%d{%Y/%m/%d %H:%M:%S}][%c][%t](%f:%l)%T%m%n"); // 自由设置日志消息输出格式 [可省略]
    
    // 设置 [扩展] 的日志落地方案
    builder->BulidSink<RollByTimeSink>("./LogFile/Base-", Type::ROLL_SECOND); // 按时间间隔滚动，阈值为 1s

    // 根据预设条件，建造日志器对象
    Yohifo::Logger::ptr logger = builder->Build();

    // 测试 10s
    time_t old = Yohifo::Util::Date::getTime();

    // 推荐使用 DEBUG 这种全大写的 [宏定义]
    //   - Debug 这种小写的 [成员函数] 需要主动传递 (文件名 + 行号)
    while(Yohifo::Util::Date::getTime() < old + 5)
        logger->FATAL("链接失败");

    return 0;
}